package UI;

import java.net.URL;
import java.net.URLConnection;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.layout.FormLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import Util.MiscUtil;

import Data.Character;
import Data.QueryException;
import Data.DbInterface;

/**
 * A shell which displays info about the given character.
 */
public class CharacterInfoShell extends Shell
{
	private Character character;
	private boolean isDeleted;
	
	private Label loadingLabel;
	
	/**
	 * Constructs the shell for the given character.
	 * 
	 * @param character The character info to display
	 */
	public CharacterInfoShell(Character character)
	{
		super(SWTUtil.getDisplay());
		
		this.character = character;
		
		FormLayout formLayout = new FormLayout();
		formLayout.marginWidth = 30;
		formLayout.marginHeight = 30;
		
		setLayout(formLayout);
		setMinimumSize(400, 400);
		
		setText(character.getName() + " info");
		
		Control prevLabel = null;
		
		prevLabel = addPropertyWidget(prevLabel, "Name", character.getName());
		prevLabel = addPropertyWidget(prevLabel, "Powers", MiscUtil.aggregateToString(character.getPower()));
		prevLabel = addPropertyWidget(prevLabel, "Species", MiscUtil.aggregateToString(character.getSpecies()));
		prevLabel = addPropertyWidget(prevLabel, "Universes", MiscUtil.aggregateToString(character.getUniverse()));
		prevLabel = addPropertyWidget(prevLabel, "Ranks", MiscUtil.aggregateToString(character.getRank()));
		prevLabel = addPropertyWidget(prevLabel, "Weight", Float.toString(character.getWeight()));
		prevLabel = addPropertyWidget(prevLabel, "Height", Float.toString(character.getHeight()));
		prevLabel = addPropertyWidget(prevLabel, "Gender", character.getGender());
		prevLabel = addPropertyWidget(prevLabel, "Medical", MiscUtil.aggregateToString(character.getMedicalCondition()));
		prevLabel = addPropertyWidget(prevLabel, "Occupation", MiscUtil.aggregateToString(character.getOccupation()));
		
		Button deleteButton = new Button(this, SWT.PUSH);
		deleteButton.setText("Delete character");
		
		FormData formData = new FormData();
		formData.left = new FormAttachment(prevLabel, 0, SWT.TRAIL);
		formData.width = 200;
		formData.top = new FormAttachment(prevLabel, 20, SWT.BOTTOM);
		formData.height = 30;
		
		deleteButton.setLayoutData(formData);
		deleteButton.addSelectionListener(new SelectionAdapter()
		{
			@Override
			public void widgetSelected(SelectionEvent e)
			{
				onDeleteClicked();
			}
		});
		
		loadingLabel = new Label(this, SWT.LEFT);
		loadingLabel.setText("Loading image...");
		
		formData = new FormData();
		formData.left = new FormAttachment(0, 380);
		formData.top = new FormAttachment(0, -5);
		formData.width = 100;
		formData.height = 20;
		
		loadingLabel.setLayoutData(formData);
		
		final Character finalChar = character;
		
		/**
		 * The image is loaded on a different thread.
		 */
		new Thread(new Runnable()
		{
			@Override
			public void run()
			{
				try
				{
					/**
					 * If a photoUrl already exists, the image is loaded from there.
					 * If not, a Google Images search is performed and the retrieved image is used and its URL is
					 * saved to the database as the photo of the character.
					 */
					String photoUrl = finalChar.getPhotoUrl();
					
					if (photoUrl.length() == 0)
					{
						photoUrl = ImageGrabber.searchImage(finalChar.getName());
						
						DbInterface.updateCharacterPhotoUrl(finalChar.getId(), photoUrl);
					}
					
					URL imageUrl = new URL(photoUrl);
					URLConnection imageConn = imageUrl.openConnection();
					
					final Image image = new Image(getDisplay(), imageConn.getInputStream());
					final String finalUrl = photoUrl;
					
					getDisplay().asyncExec(new Runnable()
					{
						@Override
						public void run()
						{
							onImageLoaded(image, finalUrl);
						}
					});
				}
				catch (Exception e)
				{
					getDisplay().asyncExec(new Runnable()
					{
						@Override
						public void run()
						{
							onImageLoadError();
						}
					});
				}
			}
		}).start();
		
		pack();
	}
	
	/**
	 * Displays the image once the image is loaded.
	 * 
	 * @param image The image data to display
	 * @param photoUrl The URL of the image which was loaded
	 */
	private void onImageLoaded(Image image, String photoUrl)
	{
		if (loadingLabel != null)
		{
			loadingLabel.setVisible(false);
		}
		
		if (!character.getPhotoUrl().equals(photoUrl))
		{
			character.setPhotoUrl(photoUrl);
		}
		
		Canvas canvas = new Canvas(this, SWT.NO_REDRAW_RESIZE | SWT.BORDER);
		
		FormData formData = new FormData();
		formData.left = new FormAttachment(0, 380);
		formData.top = new FormAttachment(0, -5);
		formData.width = image.getImageData().width;
		formData.height = image.getImageData().height;
		
		canvas.setLayoutData(formData);
		
		final Image finalImage = image;
		
		canvas.addPaintListener(new PaintListener()
		{
			@Override
			public void paintControl(PaintEvent e)
			{
				e.gc.drawImage(finalImage, 0, 0);
			}
		});
		
		pack();
	}
	
	/**
	 * If an error occurres while trying to load the image, unfortunately we can't display it...
	 */
	private void onImageLoadError()
	{
		if (loadingLabel != null)
		{
			loadingLabel.setVisible(false);
		}
	}
	
	/**
	 * Add property label and textbox with a single string.
	 * 
	 * @param after The label after which to add the controls.
	 * @param labelText The text to display on the label
	 * @param contentStr The text to display in the textbox
	 * @return The label which was added
	 */
	private Control addPropertyWidget(Control after, String labelText, String contentStr)
	{
		Label label = new Label(this, SWT.LEFT);
		label.setText(labelText + ":");
		
		FormData formData = new FormData();
		
		if (after != null)
		{
			formData.left = new FormAttachment(after, 0, SWT.LEAD);
			formData.top = new FormAttachment(after, 15, SWT.BOTTOM);
			formData.right = new FormAttachment(after, 0, SWT.TRAIL);
		}
		else
		{
			formData.left = new FormAttachment(0, 0);
			formData.top = new FormAttachment(0, 0);
			formData.width = 100;
		}
		
		formData.height = 20;
		
		label.setLayoutData(formData);
		
		Text text = new Text(this, SWT.SINGLE | SWT.BORDER);
		text.setText(contentStr);
		text.setEditable(false);
		text.setBackground(new Color(getDisplay(), 255, 255, 255));
		
		formData = new FormData();
		formData.left = new FormAttachment(label, 0, SWT.TRAIL);
		formData.top = new FormAttachment(label, -5, SWT.TOP);
		formData.width = 250;
		formData.height = 20;
		
		text.setLayoutData(formData);
		
		return label;
	}
	
	@Override
	protected void checkSubclass()
	{
		// Empty on purpose. Makes subclassing Shell possible.
	}
	
	/**
	 * Requests the user for approval, and if given, deletes the character and closes the shell.
	 * When a character is deleted the 'isDeleted' flag is raised so the search results on the
	 * army builder shell can be refreshed.
	 */
	private void onDeleteClicked()
	{
		MessageBox mb = new MessageBox(this, SWT.ICON_QUESTION |SWT.YES | SWT.NO);
		
		mb.setText("Delete");
	    mb.setMessage("Are you sure you want to delete this character?\nThis cannot be undone.");
	    
	    if (mb.open() == SWT.YES)
	    {
	    	try
	    	{
	    		DbInterface.deleteCharacter(character.getId());
	    	}
	    	catch (QueryException e)
	    	{
	    		mb = new MessageBox(this);
	    		mb.setText("Error");
	    		mb.setMessage("Unable to delete character.");
	    		mb.open();
	    	}
	    	
	    	isDeleted = true;
	    	
	    	close();
	    }
	}
	
	public boolean isCharacterDeleted()
	{
		return isDeleted;
	}
}
